package com.dmz.workflow.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dmz.workflow.entity.*;
import com.dmz.workflow.entity.Dictionary;
import com.dmz.workflow.req.ListQuery;
import com.dmz.workflow.req.ProcessInstanceReq;
import com.dmz.workflow.res.FormAdviceConguration;
import com.dmz.workflow.service.*;
import com.dmz.workflow.util.*;
import com.dmz.workflow.vo.*;
import com.dmz.workflow.wrapper.MemberFeignWrapper;
import com.echronos.commons.Result;
import com.echronos.commons.enums.ErrorMsgEnum;
import com.echronos.commons.utils.RequestUserUtils;
import com.echronos.system.feign.IMemberFeign;
import com.echronos.system.resp.MemberResp;
import com.echronos.system.resp.member.MemberDetailsResp;
import com.echronos.system.resp.member.MemberPowerResp;
import com.echronos.workflow.entity.*;
import com.echronos.workflow.res.StartProcessRes;
import com.echronos.workflow.service.*;
import com.echronos.workflow.util.*;
import com.echronos.workflow.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.task.api.Task;
import org.flowable.variable.service.impl.persistence.entity.HistoricVariableInstanceEntityImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;


@Service
public class ProcessInstanceServiceImpl implements ProcessInstanceService {
    @Autowired
    protected RuntimeService runtimeService;
    @Autowired
    protected HistoryService historyService;
    @Autowired
    protected PermissionServiceImpl permissionService;

    @Autowired
    private FlowableFormService flowableFormService;

    @Autowired
    protected TaskService taskService;

    @Autowired
    private IMemberFeign memberFeign;

    @Autowired
    private MemberFeignWrapper memberFeignWrapper;

    @Autowired
    private WorkflowNodeInfoService workflowNodeInfoService;

    @Autowired
    private WorkflowNodeExtService workflowNodeExtService;

    @Autowired
    private WorkflowDictionaryService workflowDictionaryService;

    @Autowired
    private WorkflowDiscussionService workflowDiscussionService;

    @Autowired
    private WorkflowProcessStatusService workflowProcessStatusService;

    @Autowired
    private CommonMessageManager commonMessageManager;

    @Autowired
    private ApprovalNodeService approvalNodeService;

    @Autowired
    private WorkflowProcessRelationsService workflowProcessRelationsService;

    @Autowired
    private WorkflowFormDataService workflowFormDataService;

    /**
     * 审批去重
     */
    private Integer approvalRemoveRepetition;
    /**
     * 发起人自动去重
     */
    private Integer autoApproval;

    @Override
    public ProcessInstance getProcessInstanceById(String processInstanceId) {
        ProcessInstance processInstance =
                runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance == null) {
            throw new FlowableObjectNotFoundException("No process instance found with id " + processInstanceId);
        }
        return processInstance;
    }

    @Override
    public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance =
                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (historicProcessInstance == null) {
            throw new FlowableObjectNotFoundException("No process instance found with id " + processInstanceId);
        }
        return historicProcessInstance;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<StartProcessRes> startProcess(ProcessInstanceReq processInstanceReq) {
        Integer memberId = RequestUserUtils.getUser().getMemberId();
        if (ProcessConstants.PROCESS_INSTANCE_CIRCLE_PRICE_TYPE.equals(processInstanceReq.getProcessInstanceType())) {
            memberId = processInstanceReq.getMemberId();
        }
        //去除空格获取流程定义id 和流程定key
        String processDefinitionId = StringUtils.trimToEmpty(processInstanceReq.getProcessDefinitionId());
        String processDefinitionKey = StringUtils.trimToEmpty(processInstanceReq.getProcessDefinitionKey());
        //排除异常
        if (processDefinitionId.length() == 0 && processDefinitionKey.length() == 0) {
            return Result.build(ErrorMsgEnum.NORMAL_ERR.getErrorCode(), ExceptionMessageConstants.PROCESS_DEFINITION_NOT_FOUND);
        } else if (processDefinitionId.length() != 0 && processDefinitionKey.length() != 0) {
            return Result.build(ErrorMsgEnum.NORMAL_ERR.getErrorCode(), ExceptionMessageConstants.PROCESS_DEFINITION_ID_AND_KEY_BOTH_FOUND);
        }
        List<IntermediateNodeVo> intermediateNodeVos = processInstanceReq.getNodesInfo();
        if (intermediateNodeVos.isEmpty() || (ProcessDefinitionConstants.START_NODE_NAME.equals(intermediateNodeVos.get(0).getNodeId()) && intermediateNodeVos.size() == 1)) {
            return Result.build(ErrorMsgEnum.NORMAL_ERR.getErrorCode(), ExceptionMessageConstants.PROCESS_NODE_NOT_CORRECT);
        }
        if (ProcessDefinitionConstants.DUPLICATE_NODE.equals(intermediateNodeVos.get(1).getNodeType())) {
            return Result.build(ErrorMsgEnum.NORMAL_ERR.getErrorCode(), ExceptionMessageConstants.PROCESS_SECOND_NODE_NOT_CORRECT);
        }
        // 流程发起成功后返回流程实例ID
        String processInstanceId = processStartHandler(processInstanceReq, intermediateNodeVos, memberId);
        StartProcessRes startProcessResVo = new StartProcessRes();
        startProcessResVo.setProcessInstanceId(processInstanceId);
        return Result.build(startProcessResVo);
    }

    private String processStartHandler(ProcessInstanceReq processInstanceReq, List<IntermediateNodeVo> intermediateNodeVos, Integer memberId) {
        //验证用户读取流程定义的权限
        ProcessDefinition processDefinition = permissionService.validateReadPermissionOnProcessDefinition(String.valueOf(memberId),
                processInstanceReq.getProcessDefinitionId(), processInstanceReq.getProcessDefinitionKey(), processInstanceReq.getTenantId());
        Authentication.setAuthenticatedUserId(String.valueOf(memberId));
        ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
        processInstanceBuilder.processDefinitionId(processDefinition.getId());
        processInstanceBuilder.name(processDefinition.getName());
        processInstanceBuilder.businessKey(processInstanceReq.getBusinessKey());
        boolean initiatorCheck = false;
        String starterName = "";
        List<IntermediateNodeVo> newIntermediateNodeVoList = new ArrayList<>();
        Map<String, Object> predictionParams = ConditionalDataProcessing.getStringObjectMap(processInstanceReq.getValues());
        if (ObjectUtils.isNotEmpty(predictionParams)) {
            Set<String> keySet = predictionParams.keySet();
            for (String key : keySet) {
                processInstanceBuilder.variable(key, predictionParams.get(key));
            }
        }
        processRepetitionHandler(processInstanceReq.getProcessDefinitionId(), intermediateNodeVos);
        for (IntermediateNodeVo intermediateNodeVo : intermediateNodeVos) {
            intermediateNodeVo.setCreateTime(LocalDateTime.now());
            List<Integer> idList = new ArrayList<>();
            List<StaffInfoVo> staffInfoVoList = intermediateNodeVo.getStaffInfoList();
            // 部门负责人自动转交人设置
            if (ObjectUtils.validateCollectionIsEmpty(staffInfoVoList) && ProcessDefinitionConstants.DEPARTMENT_LEADER_MEMBER.equals(intermediateNodeVo.getStatus()) && ProcessDefinitionConstants.NODE_AUTO_TRANSFER_SETTING.equals(intermediateNodeVo.getIsEmpty())) {
                MemberPowerResp memberPowerResp = memberFeign.queryAdmin(RequestUserUtils.getUser().getCompanyId());
                StaffInfoVo staffInfoVo = new StaffInfoVo();
                if (ObjectUtils.isNotEmpty(memberPowerResp)) {
                    staffInfoVo.setIdNode(intermediateNodeVo.getNodeId());
                    staffInfoVo.setTypeNode(intermediateNodeVo.getNodeType());
                    staffInfoVo.setMemberId(memberPowerResp.getId());
                    staffInfoVo.setUserId(memberPowerResp.getUserId());
                    staffInfoVo.setMemberName(memberPowerResp.getName());
                    staffInfoVo.setUrl(memberPowerResp.getAvatar());
                }
                intermediateNodeVo.setStaffInfoList(Collections.singletonList(staffInfoVo));
            }
            if (ObjectUtils.isNotEmpty(staffInfoVoList)) {
                boolean orSign = false;
                List<Integer> temStaffInfoIds = new ArrayList<>();
                for (StaffInfoVo staffInfoVo : staffInfoVoList) {
                    if (staffInfoVo.getIsRemoved() == null || staffInfoVo.getIsRemoved() == 0) {
                        if (ObjectUtils.isEmpty(intermediateNodeVo.getActivity()) || !intermediateNodeVo.getActivity().equals(ProcessDefinitionConstants.OR_SIGN)) {
                            temStaffInfoIds.add(staffInfoVo.getMemberId());
                        }
                    }
                    if (ProcessDefinitionConstants.CHECK_NODE.equals(intermediateNodeVo.getNodeType()) && ObjectUtils.isNotEmpty(intermediateNodeVo.getActivity()) && intermediateNodeVo.getActivity().equals(ProcessDefinitionConstants.OR_SIGN)) {
                        temStaffInfoIds.add(staffInfoVo.getMemberId());
                        if (ObjectUtils.isNotEmpty(staffInfoVo.getIsRemoved()) && staffInfoVo.getIsRemoved() == 1) {
                            temStaffInfoIds = null;
                            orSign = true;
                            break;
                        }
                    }
                }
                if (((ObjectUtils.isEmpty(intermediateNodeVo.getActivity()) || !intermediateNodeVo.getActivity().equals(ProcessDefinitionConstants.OR_SIGN)) && ObjectUtils.validateCollectionIsEmpty(temStaffInfoIds)) || orSign) {
                    intermediateNodeVo.setIsArrive(ProcessConstants.NODE_ARRIVED_STATUS);
                } else {
                    idList.addAll(temStaffInfoIds);
                }
                newIntermediateNodeVoList.add(intermediateNodeVo);
            }
            processInstanceBuilder.variable(intermediateNodeVo.getNodeId() + "List", idList);
            if (ProcessDefinitionConstants.START_NODE_NAME.equals(intermediateNodeVo.getNodeId())) {
                initiatorCheck = true;
                List<StaffInfoVo> staffInfoList = intermediateNodeVo.getStaffInfoList();
                if (ObjectUtils.isNotEmpty(staffInfoList)) {
                    starterName = staffInfoList.get(0).getMemberName();
                }
            }
        }
        if (!initiatorCheck) {
            throw new FlowableException("起始节点不存在。。。");
        }
        ProcessInstance processInstance = processInstanceBuilder.start();
        String processInstanceId = processInstance.getProcessInstanceId();
        // 保存表单数据
        FormData formData = new FormData();
        formData.setProcessInstanceId(processInstanceId);
        formData.setFormData(processInstanceReq.getProcessInstanceFormData());
        workflowFormDataService.save(formData);
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        for (Task task : tasks) {
            // 发起者节点为 __initiator__ ,则自动完成任务
            if (ProcessDefinitionConstants.START_NODE_NAME.equals(task.getTaskDefinitionKey())) {
                if (ObjectUtils.isEmpty(task.getAssignee())) {
                    taskService.setAssignee(task.getId(), String.valueOf(memberId));
                }
                taskService.complete(task.getId());
            }
        }
        List<IntermediateNode> intermediateNodes = new ArrayList<>();
        List<StaffInfoVo> staffInfos = new ArrayList<>();
        int nodeSeq = 0;
        boolean arrivingStatus = false;
        List<Task> currentTasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        for (IntermediateNodeVo intermediateNodeVo : newIntermediateNodeVoList) {
            if (ProcessConstants.NODE_ARRIVED_STATUS.equals(intermediateNodeVo.getIsArrive())) {
                continue;
            }
            IntermediateNode intermediateNode = new IntermediateNode();
            BeanUtils.copyProperties(intermediateNodeVo, intermediateNode);
            if (ProcessDefinitionConstants.START_NODE_NAME.equals(intermediateNodeVo.getNodeId()) || nodeSeq == 1) {
                if (nodeSeq == 1) {
                    if (ProcessDefinitionConstants.CHECK_NODE.equals(intermediateNodeVo.getNodeType())) {
                        if (!ProcessConstants.NODE_ARRIVED_STATUS.equals(intermediateNode.getIsArrive())) {
                            intermediateNode.setIsArrive(ProcessConstants.NODE_ARRIVE_STATUS);
                        } else {
                            arrivingStatus = true;
                        }
                    }
                    if (ProcessDefinitionConstants.DUPLICATE_NODE.equals(intermediateNodeVo.getNodeType())) {
                        intermediateNode.setIsArrive(ProcessConstants.NODE_ARRIVED_STATUS);
                        arrivingStatus = true;
                    }
                } else {
                    intermediateNode.setIsArrive(ProcessConstants.NODE_ARRIVED_STATUS);
                }
                for (Task task : tasks) {
                    if (task.getTaskDefinitionKey().equals(intermediateNodeVo.getNodeId())) {
                        intermediateNode.setTaskId(task.getId());
                    }
                }
            } else {
                if (arrivingStatus) {
                    if (ProcessDefinitionConstants.CHECK_NODE.equals(intermediateNodeVo.getNodeType())) {
                        if (!ProcessConstants.NODE_ARRIVED_STATUS.equals(intermediateNodeVo.getIsArrive())) {
                            intermediateNode.setIsArrive(ProcessConstants.NODE_ARRIVE_STATUS);
                            arrivingStatus = false;
                        }
                    }
                    if (ProcessDefinitionConstants.DUPLICATE_NODE.equals(intermediateNodeVo.getNodeType())) {
                        intermediateNode.setIsArrive(ProcessConstants.NODE_ARRIVED_STATUS);
                        arrivingStatus = true;
                    }
                } else {
                    intermediateNode.setIsArrive(ProcessConstants.NODE_NOT_ARRIVE_STATUS);
                }
            }
            if (!ProcessDefinitionConstants.START_NODE_NAME.equals(intermediateNodeVo.getNodeId())
                    && ObjectUtils.isNotEmpty(currentTasks)) {
                for (Task currentTask : currentTasks) {
                    if (currentTask.getTaskDefinitionKey().equals(intermediateNodeVo.getNodeId())) {
                        intermediateNode.setTaskId(currentTask.getId());
                    }
                }
            }
            intermediateNode.setCreateTime(LocalDateTime.now());
            intermediateNode.setSort(nodeSeq++);
            intermediateNode.setProcessInstanceId(processInstanceId);
            intermediateNode.setNodeTitle(intermediateNodeVo.getNodeTitle());
            intermediateNode.setApproveAlert(intermediateNodeVo.getApproveAlert());
            intermediateNode.setApproveAlertContent(intermediateNodeVo.getApproveAlertContent());
            intermediateNodes.add(intermediateNode);
            List<StaffInfoVo> staffInfoVoList = intermediateNodeVo.getStaffInfoList();
            if (ObjectUtils.isNotEmpty(staffInfoVoList)) {
                for (StaffInfoVo staffInfoVo : staffInfoVoList) {
                    if (ObjectUtils.isNotEmpty(staffInfoVo.getIsRemoved()) && staffInfoVo.getIsRemoved() == 1) {
                        continue;
                    }
                    if (ProcessDefinitionConstants.START_NODE_NAME.equals(intermediateNodeVo.getNodeId())) {
                        staffInfoVo.setStatus(ProcessApprovalConstants.MEMBER_APPROVED_STATUS);
                    } else {
                        if (!ProcessConstants.PERSON_APPROVED_STATUS.equals(staffInfoVo.getStatus())) {
                            staffInfoVo.setStatus(ProcessApprovalConstants.MEMBER_NOT_APPROVED_STATUS);
                        }
                    }
                    if (arrivingStatus && ProcessDefinitionConstants.DUPLICATE_NODE.equals(intermediateNodeVo.getNodeType())) {
                        staffInfoVo.setStatus(ProcessConstants.PERSON_APPROVED_STATUS);
                    }
                    staffInfoVo.setProcessInstanceId(processInstanceId);
                    staffInfoVo.setProcessName(processInstance.getProcessDefinitionName());
                    staffInfoVo.setCreateTime(LocalDateTime.now());
                    staffInfoVo.setNodeInfoId(intermediateNode.getId());
                    staffInfoVo.setIdNode(intermediateNode.getNodeId());
                    staffInfoVo.setTypeNode(intermediateNode.getNodeType());
                    staffInfoVo.setStarterName(starterName);
                    for (Task currentTask : currentTasks) {
                        if (staffInfoVo.getMemberId().equals(Integer.valueOf(currentTask.getAssignee())) && currentTask.getTaskDefinitionKey().equals(staffInfoVo.getIdNode())) {
                            staffInfoVo.setTaskId(currentTask.getId());
                        }
                    }
                    staffInfos.add(staffInfoVo);
                }
            }
        }
        workflowNodeInfoService.saveBatch(intermediateNodes);
        for (IntermediateNode intermediateNode : intermediateNodes) {
            for (StaffInfoVo staffInfo : staffInfos) {
                if (ObjectUtils.isEmpty(staffInfo.getIsRemoved()) || staffInfo.getIsRemoved() == 0) {
                    if (intermediateNode.getNodeId().equals(staffInfo.getIdNode())) {
                        staffInfo.setNodeInfoId(intermediateNode.getId());
                    }
                }
            }
        }
        List<StaffInfo> staffInfoList = BeanUtilsExt.copyObjectListProperties(staffInfos, StaffInfo.class);
        workflowNodeExtService.saveBatch(staffInfoList);
        ProcessInstanceStatus processInstanceStatus = new ProcessInstanceStatus();
        processInstanceStatus.setStartUser(memberId);
        Result<MemberResp> memberById = memberFeignWrapper.getMemberById(memberId);
        processInstanceStatus.setProcessInstanceId(processInstanceId);
        if (arrivingStatus) {
            processInstanceStatus.setStatus(ProcessConstants.PERSON_APPROVED_STATUS);
        } else {
            processInstanceStatus.setStatus(ProcessConstants.PROCESS_APPROVING_STATUS);
        }
        processInstanceStatus.setCompanyId(RequestUserUtils.getUser().getCompanyId());
        if (ObjectUtils.isNotEmpty(memberById.getData())) {
            processInstanceStatus.setMemberName(memberById.getData().getName());
        }
        processInstanceStatus.setProcessNo(String.valueOf(SnowFlakeUtils.getFlowIdInstance().nextId()));
        processInstanceStatus.setProcessName(processInstance.getProcessDefinitionName());
        processInstanceStatus.setCreatedTime(LocalDateTime.now());
        processInstanceStatus.setProcessInstanceType(processInstanceReq.getProcessInstanceType());
        Map<String, String> processInstanceStatusData = TemporaryStatus.getInstance().getProcessInstanceStatusData();
        String value = processInstanceStatusData.get(processInstanceId);
        if (ObjectUtils.isNotEmpty(value)) {
            processInstanceStatusData.remove(processInstanceId);
            processInstanceStatus.setStatus(ProcessConstants.PROCESS_APPROVED_STATUS);
        }
        workflowProcessStatusService.save(processInstanceStatus);
        commonMessageManager.sendAssistantMessageByProcessInstanceId(processInstanceId);
        return processInstanceId;
    }

    private void processRepetitionHandler(String processDefinitionId, List<IntermediateNodeVo> newProcessNodes) {
        FormInfo formInfo = flowableFormService.queryFormInfoByProcessDefinitionId(processDefinitionId);
        approvalRemoveRepetition = formInfo.getApprovalRemoveRepetition();
        autoApproval = formInfo.getAutoApproval();
        //连续去重处理
        if (ProcessDefinitionConstants.NODE_CONSECUTIVE_REMOVE_REPETITION.equals(approvalRemoveRepetition)) {
            processNodeConsecutiveRemoveRepetition(newProcessNodes);
        }
        // 非连续去重
        if (ProcessDefinitionConstants.NODE_LAST_KEEP_REMOVE_REPETITION.equals(approvalRemoveRepetition)) {
            processNodeKeepRemoveRepetition(newProcessNodes);
        }
        // 发起人去重
        if (ProcessDefinitionConstants.STARTER_AUTO_APPROVE.equals(autoApproval)) {
            processStarterRemoveRepetition(newProcessNodes);
        }
    }

    private void processStarterRemoveRepetition(List<IntermediateNodeVo> newProcessNodes) {
        Integer starterMemberId = newProcessNodes.get(0).getStaffInfoList().get(0).getMemberId();
        for (IntermediateNodeVo newProcessNode : newProcessNodes) {
            if (!ProcessDefinitionConstants.START_NODE_NAME.equals(newProcessNode.getNodeId())) {
                List<StaffInfoVo> staffInfoList = newProcessNode.getStaffInfoList();
                for (StaffInfoVo staffInfoVo : staffInfoList) {
                    if (newProcessNode.getNodeType().equals(ProcessDefinitionConstants.CHECK_NODE) && staffInfoVo.getMemberId().equals(starterMemberId)) {
                        staffInfoVo.setIsRemoved(1);
                    }
                }
            }
        }
    }

    private void processNodeConsecutiveRemoveRepetition(List<IntermediateNodeVo> newProcessNodes) {
        Set<Integer> memberIdSet = new HashSet<>();
        Set<Integer> temMemberIdSet;
        for (IntermediateNodeVo newProcessNode : newProcessNodes) {
            if (newProcessNode.getNodeType().equals(ProcessDefinitionConstants.CHECK_NODE) && !newProcessNode.getNodeId().equals(ProcessDefinitionConstants.START_NODE_NAME)) {
                List<StaffInfoVo> staffInfoList = newProcessNode.getStaffInfoList();
                temMemberIdSet = new HashSet<>();
                for (StaffInfoVo staffInfoVo : staffInfoList) {
                    temMemberIdSet.add(staffInfoVo.getMemberId());
                    for (Integer memberId : memberIdSet) {
                        if (staffInfoVo.getMemberId().equals(memberId)) {
                            staffInfoVo.setIsRemoved(1);
                            temMemberIdSet.add(memberId);
                        }
                    }
                }
                memberIdSet = temMemberIdSet;
            }
        }
    }

    private void processNodeKeepRemoveRepetition(List<IntermediateNodeVo> newProcessNodes) {
        Set<Integer> totalMembers = new HashSet<>();
        for (IntermediateNodeVo newProcessNode : newProcessNodes) {
            if (!newProcessNode.getNodeId().equals(ProcessDefinitionConstants.START_NODE_NAME) && ProcessDefinitionConstants.CHECK_NODE.equals(newProcessNode.getNodeType())) {
                List<StaffInfoVo> staffInfoList = newProcessNode.getStaffInfoList();
                for (StaffInfoVo staffInfoVo : staffInfoList) {
                    totalMembers.add(staffInfoVo.getMemberId());
                }
            }
        }
        for (int i = newProcessNodes.size() - 1; i >= 0; i--) {
            if (!ProcessDefinitionConstants.START_NODE_NAME.equals(newProcessNodes.get(i).getNodeId())
                    && ProcessDefinitionConstants.CHECK_NODE.equals(newProcessNodes.get(i).getNodeType())) {
                IntermediateNodeVo intermediateNodeVo = newProcessNodes.get(i);
                List<StaffInfoVo> staffInfoList = intermediateNodeVo.getStaffInfoList();
                if (!ObjectUtils.validateCollectionIsEmpty(staffInfoList)) {
                    List<StaffInfoVo> staffInfoVoList = new ArrayList<>();
                    for (StaffInfoVo staffInfoVo : staffInfoList) {
                        boolean removeFlag = true;
                        Integer neededRemoveMember = null;
                        staffInfoVo.setIsRemoved(0);
                        for (Integer member : totalMembers) {
                            if (member.equals(staffInfoVo.getMemberId())) {
                                neededRemoveMember = member;
                                removeFlag = false;
                            }
                        }
                        if (removeFlag) {
                            staffInfoVo.setIsRemoved(1);
                        }
                        staffInfoVoList.add(staffInfoVo);
                        totalMembers.remove(neededRemoveMember);
                    }
                    intermediateNodeVo.setStaffInfoList(staffInfoVoList);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.MANDATORY)
    public void deleteProcess(String processInstanceId, boolean cascade, String deleteReason) {
        HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(processInstanceId);
        if (historicProcessInstance.getEndTime() != null) {
            historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
            return;
        }
        ExecutionEntity executionEntity = (ExecutionEntity) getProcessInstanceById(processInstanceId);
        if (StringUtils.isNotEmpty(StringUtils.trimToEmpty(executionEntity.getSuperExecutionId()))) {
            throw new FlowableException("This is a subprocess");
        }
        runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
        if (cascade) {
            historyService.deleteHistoricProcessInstance(processInstanceId);
        }
    }

    @Override
    public ProcessDetailsVo getProcessDetail(String processInstanceId) {
        Integer memberId = RequestUserUtils.getUser().getMemberId();
        ProcessDetailsVo processDetailsVo = new ProcessDetailsVo();
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        // 获取表单数据
        FormData formData = workflowFormDataService.selectFormDataByProcessInstanceId(processInstanceId);
        if (ObjectUtils.isEmpty(formData)) {
            HistoricVariableInstanceEntityImpl processInstanceFormData =
                    (HistoricVariableInstanceEntityImpl) historyService.createHistoricVariableInstanceQuery()
                            .processInstanceId(processInstanceId).variableName(ProcessDefinitionConstants.PROCESS_DEFINITION_FORM_NAME).singleResult();
            processDetailsVo.setProcessFormDate(processInstanceFormData.getTextValue());
        } else {
            processDetailsVo.setProcessFormDate(formData.getFormData());
        }
        processDetailsVo.setProcessName(historicProcessInstance.getName());
        // 获取流程节点信息
        List<IntermediateNode> intermediateNodes = workflowNodeInfoService.selectIntermediateNodesByProcessInstanceId(processInstanceId);
        List<IntermediateNodeVo> intermediateNodeVos = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(intermediateNodes)) {
            intermediateNodeVos = BeanUtilsExt.copyObjectListProperties(intermediateNodes, IntermediateNodeVo.class);
        }
        // 获取评论信息
        List<Discussion> discussions = workflowDiscussionService.selectDiscussionByProcessInstanceId(processInstanceId);
        List<DiscussionVo> discussionVos = new ArrayList<>();
        List<Integer> discussionMemberIds = new ArrayList<>();
        List<MemberDetailsResp> discussionMemberList = null;
        if (ObjectUtils.isNotEmpty(discussions)) {
            for (Discussion discussion : discussions) {
                discussionMemberIds.add(discussion.getCreateUser());
            }
            // 获取评论节点人员的头像
            discussionMemberList = memberFeignWrapper.queryMemberDetailList(discussionMemberIds);
            discussionVos = BeanUtilsExt.copyObjectListProperties(discussions, DiscussionVo.class);
        }
        // 获取附件信息
        List<Dictionary> dictionaries = workflowDictionaryService.selectDictionaryByProcessInstanceId(processInstanceId);
        List<DictionaryVo> dictionaryVos = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(dictionaries)) {
            dictionaryVos = BeanUtilsExt.copyObjectListProperties(dictionaries, DictionaryVo.class);
        }
        ProcessInstanceStatus processInstanceStatus = workflowProcessStatusService.selectInstanceByInstanceId(processInstanceId);
        // 获取节点上人员的头像
        List<StaffInfo> staffCollection = getMemberAvatarInfo(processInstanceId);
        for (IntermediateNodeVo intermediateNodeVo : intermediateNodeVos) {
            List<DiscussionVo> discussionVOS = new ArrayList<>();
            for (DiscussionVo discussionVo : discussionVos) {
                for (MemberDetailsResp memberDetailsResp : discussionMemberList) {
                    if (memberDetailsResp.getMemberId().equals(discussionVo.getCreateUser())) {
                        discussionVo.setMemberName(memberDetailsResp.getMemberName());
                        discussionVo.setUrl(memberDetailsResp.getAvatar());
                    }
                }
                if (discussionVo.getNodeId().equals(intermediateNodeVo.getNodeId())) {
                    discussionVOS.add(discussionVo);
                }
                List<DictionaryVo> commentDictionaryVOList = new ArrayList<>();
                for (DictionaryVo dictionaryVO : dictionaryVos) {
                    if (String.valueOf(discussionVo.getId()).equals(dictionaryVO.getCode()) && ProcessConstants.ATTACHMENT_BELONG_TO_COMMENT.equals(dictionaryVO.getBelongTo())) {
                        commentDictionaryVOList.add(dictionaryVO);
                    }
                }
                discussionVo.setDictionaryVOList(commentDictionaryVOList);
            }
            List<StaffInfoVo> staffObjVo = new ArrayList<>();
            List<StaffInfoVo> newStaffObjVo = new ArrayList<>();
            List<StaffInfoVo> transferStaffInfo = new ArrayList<>();
            for (StaffInfo staffVo : staffCollection) {
                if (ProcessConstants.PROCESS_APPROVED_STATUS.equals(processInstanceStatus.getStatus()) && staffVo.getMemberId().equals(memberId)) {
                    staffVo.setReadStatus(1);
                    workflowNodeExtService.updateCcReadStatusByStatus(new String[]{staffVo.getProcessInstanceId()}, memberId);
                }
                if (intermediateNodeVo.getId().equals(staffVo.getNodeInfoId()) ||
                        (staffVo.getIdNode().equals(intermediateNodeVo.getNodeId()) && ObjectUtils.isEmpty(staffVo.getNodeInfoId()))) {
                    List<DictionaryVo> approveDictionaryVOList = new ArrayList<>();
                    for (DictionaryVo dictionaryVO : dictionaryVos) {
                        boolean flag = dictionaryVO.getCode().equals(String.valueOf(intermediateNodeVo.getNodeId()))
                                && ProcessConstants.ATTACHMENT_BELONG_TO_APPROVAL.equals(dictionaryVO.getBelongTo())
                                && dictionaryVO.getCreateUser().equals(staffVo.getMemberId());
                        if (flag) {
                            approveDictionaryVOList.add(dictionaryVO);
                        }
                    }
                    StaffInfoVo staffInfoVo = new StaffInfoVo();
                    BeanUtils.copyProperties(staffVo, staffInfoVo);
                    if (ObjectUtils.isNotEmpty(staffVo.getTargetMemberId())) {
                        transferStaffInfo.add(staffInfoVo);
                    }
                    staffInfoVo.setDictionaryVOList(approveDictionaryVOList);
                    staffObjVo.add(staffInfoVo);
                }

                // 根据人员信息返回task id
                if (ProcessDefinitionConstants.CHECK_NODE.equals(intermediateNodeVo.getNodeType()) && intermediateNodeVo.getNodeId().equals(staffVo.getIdNode())) {
                    if (staffVo.getMemberId().equals(memberId) && ObjectUtils.isNotEmpty(staffVo.getTaskId())) {
                        intermediateNodeVo.setTaskId(staffVo.getTaskId());
                    }
                    if (Integer.valueOf(historicProcessInstance.getStartUserId()).equals(memberId) && ObjectUtils.isNotEmpty(staffVo.getTaskId())) {
                        intermediateNodeVo.setTaskId(staffVo.getTaskId());
                    }
                }
            }
            if (!ObjectUtils.validateCollectionIsEmpty(transferStaffInfo)) {
                List<StaffInfoVo> transferedStaffInfo = new ArrayList<>();
                // 获取转交人的信息
                for (StaffInfoVo infoVo : transferStaffInfo) {
                    for (StaffInfoVo staffInfoVo : staffObjVo) {
                        if (staffInfoVo.getMemberId().equals(Integer.valueOf(infoVo.getTargetMemberId()))) {
                            transferedStaffInfo.add(staffInfoVo);
                        }
                    }
                }
                // 转交人和被转交人排序
                for (StaffInfoVo staffInfoVo : staffObjVo) {
                    boolean normalFlag = false;
                    boolean transferedFlag = false;
                    StaffInfoVo transferedStaffInfoVo = new StaffInfoVo();
                    for (StaffInfoVo infoVo : transferedStaffInfo) {
                        if (staffInfoVo.getMemberId().equals(infoVo.getMemberId())) {
                            normalFlag = true;
                        }
                        if (ObjectUtils.isNotEmpty(staffInfoVo.getTargetMemberId()) && infoVo.getMemberId().equals(Integer.valueOf(staffInfoVo.getTargetMemberId()))) {
                            transferedFlag = true;
                            transferedStaffInfoVo = infoVo;
                        }
                    }
                    if (!normalFlag) {
                        newStaffObjVo.add(staffInfoVo);
                    }
                    if (transferedFlag) {
                        newStaffObjVo.add(transferedStaffInfoVo);
                    }
                }
                staffObjVo = newStaffObjVo;
            }
            intermediateNodeVo.setDiscussionVOList(discussionVOS);
            intermediateNodeVo.setStaffInfoList(staffObjVo);
        }

        if (ObjectUtils.isNotEmpty(processInstanceStatus)) {
            processDetailsVo.setStatus(processInstanceStatus.getStatus());
            processDetailsVo.setProcessNo(StringUtils.isNotEmpty(processInstanceStatus.getProcessNo()) ? processInstanceStatus.getProcessNo() : " ");
        }
        // 审批意见配置查询
        FormInfo formInfo = flowableFormService.queryFormInfoByProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
        if (ObjectUtils.isNotEmpty(formInfo)) {
            processDetailsVo.setApprovalAdviceType(formInfo.getApprovalAdviceType());
            processDetailsVo.setApprovalAdvice(formInfo.getApprovalAdvice());
            processDetailsVo.setSignature(formInfo.getSignature());
        }
        processDetailsVo.setIntermediateNodeVo(intermediateNodeVos);
        Boolean isStarter = memberId.equals(Integer.valueOf(historicProcessInstance.getStartUserId()));
        processDetailsVo.setIsStarter(isStarter);
        Map<String, Object> requestParameter = new HashMap<>();
        requestParameter.put("memberId", memberId);
        requestParameter.put("processInstanceId", processInstanceId);
        int result = approvalNodeService.queryMemberApprovingTask(requestParameter);
        Set<String> usedConditions = approvalNodeService.queryUsedConditions(historicProcessInstance.getProcessDefinitionId());
        processDetailsVo.setUsedConditions(usedConditions);
        Boolean isApprover = result > 0;
        processDetailsVo.setIsApprover(isApprover);
        if (isApprover && isStarter) {
            processDetailsVo.setButtonPermissions(ButtonPermissionEnums.STARTER_AND_APPROVE_PERMISSION.value);
        } else if (isApprover) {
            processDetailsVo.setButtonPermissions(ButtonPermissionEnums.APPROVER_PERMISSION.value);
        } else if (isStarter) {
            processDetailsVo.setButtonPermissions(ButtonPermissionEnums.STARTER_PERMISSION.value);
        } else {
            processDetailsVo.setButtonPermissions(ButtonPermissionEnums.VIEW_DETAIL_PERMISSION.value);
        }
        if (!ProcessConstants.PROCESS_APPROVING_STATUS.equals(processInstanceStatus.getStatus())) {
            processDetailsVo.setButtonPermissions(ButtonPermissionEnums.VIEW_DETAIL_PERMISSION.value);
        }
        ProcessRelations processRelations = workflowProcessRelationsService.queryProcessSessionId(processInstanceId);
        if (ObjectUtils.isNotEmpty(processRelations)) {
            processDetailsVo.setSessionId(processRelations.getSessionId());
        }
        return processDetailsVo;
    }

    @Override
    public Result<List<TaskListVo>> listStartedByMe(ListQuery queryVo) {
        String memberId = String.valueOf(RequestUserUtils.getUser().getMemberId());
        Integer pageSize = queryVo.getPageSize();
        Integer pageNo = queryVo.getPageNo();
        IPage<ProcessInstanceStatus> instanceStatusIPage =
                workflowProcessStatusService.selectProcessInstanceIdsByStatus(memberId, queryVo.getStatus(), pageNo, pageSize, queryVo.getKeyword());
        long size = 0;
        List<TaskListVo> taskListVos = new ArrayList<>();
        List<ProcessInstanceStatus> records = instanceStatusIPage.getRecords();
        if (ObjectUtils.isNotEmpty(records)) {
            Map<String, Integer> processInstancesIdsAndStatus = new HashMap<>();
            for (ProcessInstanceStatus record : records) {
                processInstancesIdsAndStatus.put(record.getProcessInstanceId(), record.getStatus());
            }
            HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
            List<HistoricProcessInstance> historicProcessInstances;
            historicProcessInstances = historicProcessInstanceQuery.processInstanceIds(processInstancesIdsAndStatus.keySet()).orderByProcessInstanceStartTime().desc().list();
            size = instanceStatusIPage.getTotal();
            List<MemberDetailsResp> memberDetailsResps = memberFeignWrapper.queryMemberDetailList(Collections.singletonList(RequestUserUtils.getUser().getMemberId()));
            MemberInfoVo memberResp = null;
            if (ObjectUtils.isNotEmpty(memberDetailsResps)) {
                MemberDetailsResp memberDetailsResp = memberDetailsResps.get(0);
                memberResp = MemberInfoVo.builder()
                        .url(memberDetailsResp.getAvatar())
                        .name(memberDetailsResp.getMemberName())
                        .phone(memberDetailsResp.getPhone())
                        .id(memberDetailsResp.getMemberId())
                        .build();
            }
            for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
                TaskListVo taskListVO = new TaskListVo();
                taskListVO.setMemberResp(memberResp);
                taskListVO.setProcessInstanceId(historicProcessInstance.getId());
                taskListVO.setProcessName(historicProcessInstance.getName());
                taskListVO.setStarTime(historicProcessInstance.getStartTime() != null ? LocalDateTime.ofInstant(historicProcessInstance.getStartTime().toInstant(), ZoneId.systemDefault()) : null);
                taskListVO.setEndTime(historicProcessInstance.getEndTime() != null ? LocalDateTime.ofInstant(historicProcessInstance.getEndTime().toInstant(), ZoneId.systemDefault()) : null);
                taskListVO.setStatus(processInstancesIdsAndStatus.get(historicProcessInstance.getId()));
                taskListVos.add(taskListVO);
            }
        }
        return Result.build(taskListVos, size);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void activate(String processInstanceId) {
        ProcessInstance processInstance = getProcessInstanceById(processInstanceId);
        if (!processInstance.isSuspended()) {
            throw new FlowableException("Process instance is not suspended with id " + processInstanceId);
        }
        runtimeService.activateProcessInstanceById(processInstance.getId());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void suspend(String processInstanceId) {
        ProcessInstance processInstance = getProcessInstanceById(processInstanceId);
        if (processInstance.isSuspended()) {
            throw new FlowableException("Process instance is already suspended with id {0}" + processInstanceId);
        }
        runtimeService.suspendProcessInstanceById(processInstance.getId());
    }

    @Override
    public List<MemberDetailsResp> queryProcessInvolvedMembers(String processInstanceId) {
        List<Object> memberIds = workflowNodeExtService.selectProcessInvolvedMembers(processInstanceId);
        List<MemberDetailsResp> memberDetailsResps = null;
        if (!ObjectUtils.validateCollectionIsEmpty(memberIds)) {
            List<Integer> queryMemberIds = new ArrayList<>();
            for (Object memberId : memberIds) {
                queryMemberIds.add((Integer) memberId);
            }

            memberDetailsResps = memberFeignWrapper.queryMemberDetailList(queryMemberIds);
        }
        return memberDetailsResps;
    }

    @Override
    public FormAdviceConguration queryFormConfiguration(String processInstanceId) {
        FormAdviceConguration formAdviceConguration = new FormAdviceConguration();
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        // 审批意见配置查询
        FormInfo formInfo = flowableFormService.queryFormInfoByProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
        if (ObjectUtils.isNotEmpty(formInfo)) {
            formAdviceConguration.setApprovalAdviceType(formInfo.getApprovalAdviceType());
            formAdviceConguration.setApprovalAdvice(formInfo.getApprovalAdvice());
            formAdviceConguration.setSignature(formInfo.getSignature());
        }
        String startUserId = historicProcessInstance.getStartUserId();
        Result<MemberResp> memberById = memberFeignWrapper.getMemberById(Integer.valueOf(startUserId));
        if (memberById.isSuccess()) {
            MemberResp data = memberById.getData();
            formAdviceConguration.setStarterMemberInfo(MemberInfoVo.builder().id(data.getId()).name(data.getName())
                    .url(data.getUrl()).userId(data.getUserId())
                    .build());
        }
        return formAdviceConguration;
    }

    private List<StaffInfo> getMemberAvatarInfo(String processInstanceId) {
        List<StaffInfo> staffCollection = workflowNodeExtService.selectListByProcessInstanceIdAndNodeType(processInstanceId, null);
        List<Integer> memberIds = new ArrayList<>();
        for (StaffInfo staffInfo : staffCollection) {
            memberIds.add(staffInfo.getMemberId());
        }
        List<MemberDetailsResp> nodeMemberDetails = memberFeignWrapper.queryMemberDetailList(memberIds);
        if (ObjectUtils.isNotEmpty(nodeMemberDetails)) {
            for (StaffInfo staffInfo : staffCollection) {
                for (MemberDetailsResp memberDetailsResp : nodeMemberDetails) {
                    if (staffInfo.getMemberId().equals(memberDetailsResp.getMemberId())) {
                        staffInfo.setUrl(memberDetailsResp.getAvatar());
                        if (!CommonConstants.PLATFORM_MANAGER_NAME.equals(staffInfo.getMemberName())) {
                            staffInfo.setMemberName(memberDetailsResp.getMemberName());
                        }
                        break;
                    }
                }
            }
        }
        return staffCollection;
    }
}
